#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <time.h>
#include <stdlib.h>
#include <string>
#include <cstring>
#include <vector>
#include <sstream>
#include <exception>
#include <limits.h>
#include <sstream>
#include <stdio.h>//debug
////
#include <sys/mman.h>
#include <sys/stat.h>        /* For mode constants */
#include <fcntl.h>           /* For O_* constants */
#include <sys/sem.h>    //semafory
///

#define    READ    0
#define    WRITE    1

#define       DELETE 68 //D
#define    LINPUT 73 //I
#define    LOUTPUT 79 //O
#define    LREAD 82 //R

#define    NRPROC 9

#define ERROR_CREATING_PIPE -1

#define SIZE_PIPE_DATA 512
#define SIZE_OF_PIPE PIPE_BUF

#define MAX_TUPLES 32    //Maksymalna liczba krotek do testow na razie mala liczba

#define    EQUAL    0
#define GT    1
#define    GTE    2
#define LT    3
#define LTE    4


class InvalidConditionException : public std::exception
{
    public:
    virtual const char* what() const throw()
    {
        return "Invalid condition received, returning\n";
    }
};

class InvalidOperatorException : public std::exception
{
    public:
    virtual const char* what() const throw()
    {
        return "Invalid operator received, returning\n";
    }
};

class InvalidStringFormatException : public std::exception
{
    public:
    virtual const char* what() const throw()
    {
        return "Text string not in \" \", returning\n";
    }
};

class GeneralConditionException : public std::exception
{
    public:
    virtual const char* what() const throw()
    {
        return "No condition to process, returning\n";
    }
};

class TupleNotFoundException : public std::exception
{
    public:
    virtual const char* what() const throw()
    {
        return "Requested tuple hasn't been found\n";
    }
};

//Definicja pojedynczego elementu krotki- jest to albo string albo integer- sprawdza się to przez flagę isInteger
struct Element
{
    Element(std::string elementString)
    {
        eString = elementString;
        isInteger = false;
    }
    Element(int elementInteger)
    {
        eInteger = elementInteger;
        isInteger = true;
    }
    int operator==(const Element & other) const
    {
        return (eString == other.eString && eInteger == other.eInteger && isInteger == other.isInteger);
    }
    std::string eString;
    int eInteger;
    bool isInteger; //do sprawdzania, czy integer, czy string
};

//Definicja krotki
typedef std::vector<Element> Tuple;

#define LINKED_TO_MAIN  //po to by nie dołączał wielokrotnie tych samych rzeczy
#include "childFunction.h"

//deklaracje funkcji
void parentFunction(int* requestPipe, pid_t* childPidTable, int answerPipes[NRPROC][2]);
//void childFunction(int numChild, int* requestPipe, int* answerPipes);
void requestHandler(char * readBuffer, char * answerBuffer, std::vector<Tuple>& tuples, std::vector<std::string> &tupleRequests, int* offset /*out*/, int* addressee /*out*/, int answerPipes[NRPROC][2] );
std::vector<int> findIndexesOfRequests(char* readBuffer);
int getOperationFromBuffer(char * readBuffer);
//void createRequest(int numChild, char* requestBuffer);
void linda_input(char * readBuffer, char * answerBuffer, std::vector<Tuple> &tuples);
void linda_read(char * readBuffer, char * answerBuffer, std::vector<Tuple> &tuples);
void linda_output(char * readBuffer, char * answerBuffer, std::vector<Tuple> &tuples, std::vector<std::string> &tupleRequests, int answerPipes[NRPROC][2]);
void matchTuples(std::string condition, std::vector<Tuple> &tuples, unsigned index);
void matchTuplesSize(std::vector<Tuple> &tuples, unsigned size);
std::string convertTupleToString(Tuple tuple);
void removeTupleFromVector(std::vector<Tuple> &tuples, Tuple &tuple);
void linda_match(char * readBuffer, char * answerBuffer, std::vector<Tuple> &tuples);
bool checkIfStringComparision(std::string condition);
int getOperatorType(std::string condition, size_t operator_pos, int & operatorLength);
std::string getConditionValue(std::string condition, size_t operator_pos, int operatorLength, bool stringComparision);
void filterTuples(std::vector<Tuple> &tuples, std::string value, int operatorType, unsigned index, bool stringComparision);
void deleteFromTupleRequests(char * readBuffer, char* answerBuffer, std::vector<std::string> &tupleRequests);

//semafor na konsole
int consoleSemaphore;
sembuf sembufWait, sembufPost;

int main(int argc, char **argv)
{
    //semafor na konsole
    consoleSemaphore=semget (IPC_PRIVATE, 1, 0666 | IPC_CREAT);
    sembufPost.sem_num=sembufWait.sem_num=0;
    sembufWait.sem_op=-1;
    sembufPost.sem_op=1;
    semop(consoleSemaphore, &sembufPost, 1); //Post

    //argumenty wywołania
    int startupCode;
    std::ifstream sourceRequestFile;

    if(argc>3 || (argc>=2 && argv[1][0]!='A' && argv[1][0]!='M')) {
        std::cout<<"wywolanie: ./main [A|M] [<plik z zapytaniami>]"<<std::endl;
        std::cout<<"\tA==automatyczna generacja zapytan przez potomkow"<<std::endl;
        std::cout<<"\tM==generacja zapytan z pliku <plik z zapytaniami>"<<std::endl;
        return 0;
    }
    if(argc>1) {
        if(argv[1][0]=='A')    startupCode=startupCode_Automatic;
        if(argv[1][0]=='M')    startupCode=startupCode_FromFile;
        if(argc==3) {
          sourceRequestFile.open(argv[2]);
          if(!sourceRequestFile.is_open()) {
            std::cout<<"podany plik <plik z zapytaniami> nie istnieje; \n cos pomyliles, albo plik jest w innym katalogu niz plik wykonywalny;"<<std::endl;
            return 0;
          }
        }
    }

    pid_t childsPidTable[NRPROC]; //Proces macierzysty przechowuje pidy swoich potomków
    int requestPipe[2];
    int answerPipes[NRPROC][2];

    int procs=0;
    pid_t pid;

    srand(time(NULL));

    if(pipe(requestPipe)!=0)
        return ERROR_CREATING_PIPE;

    for(procs=0; procs<NRPROC; procs++)
    {
        if(pipe(answerPipes[procs])!=0)
            return ERROR_CREATING_PIPE;

        pid=fork();

        if(pid==0)
            break;
        else
            childsPidTable[procs]=pid;
    }

    if(pid!=0)
        parentFunction(requestPipe, childsPidTable, answerPipes);
    else {
        if(startupCode==startupCode_Automatic)
            childFunction(procs, requestPipe, answerPipes[procs], startupCode_Automatic);
        if(startupCode==startupCode_FromFile) {
            std::ifstream copy_sourceRequestFile;
            copy_sourceRequestFile.open(argv[2]);
            childFunction(procs, requestPipe, answerPipes[procs], startupCode_FromFile, &copy_sourceRequestFile);
        }

    }

    return 0;
}

// @TODO przetestuj
void parentFunction(int* requestPipe, pid_t* childPidTable, int answerPipes[NRPROC][2])
{
    std::ofstream myOutputParentFile;
    myOutputParentFile.open("parent.txt");

    std::vector<Tuple> Tuples;    //zestaw przetrzymywanych krotek
    std::vector<std::string> tupleRequests;
    char readBuffer[SIZE_OF_PIPE];
    char answerBuffer[SIZE_PIPE_DATA];

    //Czyścimy ładnie bufor readBuffer służący jako miejce w które read(..) kopiuje zawartość potoku
    for(int i=0; i<SIZE_PIPE_DATA; ++i)
        readBuffer[i]=0;

    //Zamykamy niepotrzebne deskryptory: requestPipe[WRITE], answerPipes[i][READ]
    for(int i=0; i<NRPROC; i++)
        close(answerPipes[i][READ]);
    close(requestPipe[WRITE]);

    //Wypisujemy potomków
    semop(consoleSemaphore, &sembufWait, 1); //Wait
    std::cout<<"\n\n------->>RODZIC:";
    std::cout<<"\n\tLista Potomkow:\n";
    for(int i=0; i<NRPROC; i++)
        std::cout<<"\t\tPotomek PID=="<<childPidTable[i]<<std::endl;
    std::cout<<"------->>RODZIC."<<std::endl<<std::endl;
    semop(consoleSemaphore, &sembufPost, 1); //Post
    //
    myOutputParentFile<<"\n\n------->>RODZIC:";
    myOutputParentFile<<"\n\tLista Potomkow:\n";
    for(int i=0; i<NRPROC; i++)
        myOutputParentFile<<"\t\tPotomek PID=="<<childPidTable[i]<<std::endl;
    myOutputParentFile<<"------->>RODZIC."<<std::endl<<std::endl;

    //Pętla nasłuchiwania
    while(1)
    {
        read(requestPipe[READ], readBuffer, SIZE_OF_PIPE);

        //Znalezienie pozycji w tablicy readBuffer odpowiadających kolejnym requestom;
        std::vector<int> indexesOfRequests = findIndexesOfRequests(readBuffer);
        int numRequests=indexesOfRequests.size();

        //Drukujemy odebrane requesty:
        semop(consoleSemaphore, &sembufWait, 1); //Wait
        std::cout<<"\n\n------->>RODZIC:";
        for(int i=0; i<numRequests; ++i) {
            std::cout<<"\n\todebrano request: \n\t\t"<<readBuffer+indexesOfRequests[i]<<std::endl;
        }
        std::cout<<"------->>RODZIC."<<std::endl<<std::endl;
        semop(consoleSemaphore, &sembufPost, 1); //Post
        //
        myOutputParentFile<<"\n\n------->>RODZIC:";
        for(int i=0; i<numRequests; ++i) {
             myOutputParentFile<<"\n\todebrano request: \n\t\t"<<readBuffer+indexesOfRequests[i]<<std::endl;
        }
         myOutputParentFile<<"------->>RODZIC."<<std::endl<<std::endl;

        //Obsługujemy każdego requesta
        for(int i=0; i<numRequests; ++i) {
            int offset; //ile znakow trzeba uciac zbednych z answerBuffer wygenerowanego przez requestHandler
            int addressee; //numer id dziecka do ktorego nalezy wyslac bedzie answerBufferaa
            try
            {
                requestHandler(readBuffer+indexesOfRequests[i], answerBuffer, Tuples, tupleRequests, &offset, &addressee, answerPipes );
                write(answerPipes[addressee][WRITE], answerBuffer+offset, strlen(answerBuffer));

                //Drukujemy odpowiedz
                semop(consoleSemaphore, &sembufWait, 1); //Wait
                std::cout<<"\n\n------->>RODZIC:";
                std::cout<<"\n\trodzic wyslal wiadomosc do potomka"<< addressee <<" o tresci: \n\t\t"<<answerBuffer+offset<<std::endl;
                std::cout<<"------->>RODZIC."<<std::endl<<std::endl;
                semop(consoleSemaphore, &sembufPost, 1); //Post
                //
                myOutputParentFile<<"\n\n------->>RODZIC:";
                myOutputParentFile<<"\n\trodzic wyslal wiadomosc do potomka"<< addressee <<" o tresci: \n\t\t"<<answerBuffer+offset<<std::endl;
                myOutputParentFile<<"------->>RODZIC."<<std::endl<<std::endl;
            }
            catch(TupleNotFoundException &e)
            {
                 semop(consoleSemaphore, &sembufWait, 1); //Wait
                 std::cout<<"\n\n------->>RODZIC:";
                 std::cout<<"\n\twstawiam do pamieci request: \n\t\t"<<readBuffer+indexesOfRequests[i]<<std::endl;
                 std::cout<<"------->>RODZIC."<<std::endl<<std::endl;
                 semop(consoleSemaphore, &sembufPost, 1); //Post
                 
                 tupleRequests.push_back(std::string(readBuffer+indexesOfRequests[i]));

            }

        }

        //Czyścimy ładniutko readBuffer zerując elementy co zostały w ostatnim przebiegu skopiowane z read(..)
        int idxOfLast=indexesOfRequests.back()+strlen(readBuffer+indexesOfRequests.back());
        for(int i=0; i<idxOfLast; ++i)
            readBuffer[i]=0;
    }

     myOutputParentFile.close();
     // @TODO zniszcz semafora
}

/*!
    /param offset out ile pierwszych znaków z answerBuffer zbędnych trzeba uciąć (<numer adresata>.)
    /param addressee out identyfikator potomka do którego należy wysłać wiadomość
*/
void requestHandler(char * readBuffer, char * answerBuffer, std::vector<Tuple>& tuples, std::vector<std::string>& tupleRequests, int* offset /*out*/, int* addressee /*out*/, int answerPipes[NRPROC][2] )
{
    int operation = getOperationFromBuffer(readBuffer);
    switch(operation) {
        case LINPUT:
            linda_input(readBuffer, answerBuffer, tuples);
            break;
        case LOUTPUT:
            linda_output(readBuffer, answerBuffer, tuples, tupleRequests, answerPipes);
            break;
        case LREAD:
            linda_read(readBuffer, answerBuffer, tuples);
            break;
        case DELETE:
            deleteFromTupleRequests(readBuffer, answerBuffer, tupleRequests);
            break;
    }

    //komu odeslac wiadomość: wpisujemy w offset i addressee
    std::string answerBufferString(answerBuffer);
    std::string addresseeString =answerBufferString.substr (0, answerBufferString.find("."))  ;
    (*addressee)=atoi(addresseeString.c_str());
    (*offset)=addresseeString.length()+1;

    return;
}

std::vector<int> findIndexesOfRequests(char* readBuffer) {
    int position=0;
    std::vector<int> indexesOfRequests;

    while(readBuffer[position]) {
        indexesOfRequests.push_back(position);
        while(readBuffer[position])
            ++position;
        ++position;
    }
    return indexesOfRequests;
}

// @TODO: workPoints = 2 Zaimplementować
int getOperationFromBuffer(char * readBuffer)
{
    int a;
    std::string readBufferString(readBuffer);
    std::string opNumber = readBufferString.substr(readBufferString.find(".")+1, 1);
    a=(opNumber.c_str()[0]);
    return a;
}


void linda_match(char * readBuffer, char * answerBuffer, std::vector<Tuple> &tuples, bool remove)
{
    std::string readBufferString(readBuffer);
    // we need to find childNumber that sent the request
    std::string childNumber = readBufferString.substr(0, readBufferString.find("."));
    //printf("Child number is: %s\n", childNumber.c_str());
    // now since we know the child number, we may focus solely on request content
    readBufferString = readBufferString.substr(readBufferString.find(".", readBufferString.find(".") + 1) + 1);
    std::string tupleString;

    std::vector<Tuple> helpTuples(tuples);
    bool stop = false;
    size_t pos = 0;
    unsigned index = 0;
    while(!stop)
    {
        pos = readBufferString.find(",");
        if(pos == std::string::npos || helpTuples.size() == 0)
            stop = true;
        std::string condition(readBufferString.substr(0, pos));
        readBufferString = readBufferString.substr(pos + 1);
        try
        {
            matchTuples(condition, helpTuples, index++);
        }
        catch(InvalidConditionException &e)
        {
            perror(e.what());
            std::string answerBufferString = childNumber + "." + "InvalidConditionException";
            strcpy(answerBuffer, answerBufferString.c_str());
            return;
        }
        catch(InvalidOperatorException &e)
        {
            perror(e.what());
            std::string answerBufferString = childNumber + "." + "InvalidOperatorException";
            strcpy(answerBuffer, answerBufferString.c_str());
            return;
        }
        catch(InvalidStringFormatException &e)
        {
            perror(e.what());
            std::string answerBufferString = childNumber + "." + "InvalidStringFormatException";
            strcpy(answerBuffer, answerBufferString.c_str());
            return;
        }
    }

    matchTuplesSize(helpTuples, index);

    if(helpTuples.size() != 0)
    {
        tupleString = convertTupleToString(helpTuples[0]);
    }
    else
    {
        throw TupleNotFoundException();
    }

    std::string answerBufferString = childNumber + "." + tupleString;
    //printf("Zwroce nastepujaca krotke: %s\n", answerBufferString.c_str());
    strcpy(answerBuffer, answerBufferString.c_str());

    if(remove)
        removeTupleFromVector(tuples, helpTuples[0]);

    /*printf("helpTuples:\n");
    for(int i = 0; i < helpTuples.size(); i++)
    {
        for(int j = 0; j < helpTuples[i].size(); j++)
        {
            if(helpTuples[i][j].isInteger)
                printf("%d,", helpTuples[i][j].eInteger);
            else
                printf("%s,", helpTuples[i][j].eString.c_str());
        }
        printf("\n");
    }
    printf("\n");*/
}

// @TODO: workPoints = 7 Zaimplementować - łączne z linda_read
void linda_input(char * readBuffer, char * answerBuffer, std::vector<Tuple> &tuples)
{
    linda_match(readBuffer, answerBuffer, tuples, true);
}

// @TODO: workPoints = 7 Zaimplementować - łączne z linda_input
void linda_read(char * readBuffer, char * answerBuffer, std::vector<Tuple> &tuples)
{
    linda_match(readBuffer, answerBuffer, tuples, false);
}

void matchTuples(std::string condition, std::vector<Tuple> &tuples, unsigned index)
{
    try
    {
        bool stringComparision = checkIfStringComparision(condition);
        size_t operator_pos;
        if(stringComparision)
            operator_pos = 6;
        else
            operator_pos = 7;
        int operatorLength = 1;
        int operatorType = getOperatorType(condition, operator_pos, operatorLength);
        std::string value = getConditionValue(condition, operator_pos, operatorLength, stringComparision);
        filterTuples(tuples, value, operatorType, index, stringComparision);
    }
    catch(GeneralConditionException &e)
    {
        // everything is ok, just return
        return;
    }
    catch(InvalidConditionException &e)
    {
        throw InvalidConditionException();
    }
    catch(InvalidOperatorException &e)
    {
        throw InvalidOperatorException();
    }
    catch(InvalidStringFormatException &e)
    {
        throw InvalidStringFormatException();
    }
}

void matchTuplesSize(std::vector<Tuple> &tuples, unsigned size)
{
    for(std::vector<Tuple>::iterator it = tuples.begin(); it != tuples.end(); ++it)
    {
        if(it->size() != size)
            tuples.erase(it--);
    }
}

std::string convertTupleToString(Tuple tuple)
{
    std::stringstream ss;
    for(unsigned i = 0; i < tuple.size(); i++)
    {
        if(tuple[i].isInteger)
        {
            ss << tuple[i].eInteger;
            ss << ",";
        }
        else
            ss << '"' + tuple[i].eString + "\",";
    }
    std::string response;
    ss >> response;
    return response.substr(0, response.size() - 1);
}

void removeTupleFromVector(std::vector<Tuple> &tuples, Tuple &tuple)
{
    for(std::vector<Tuple>::iterator it = tuples.begin(); it != tuples.end(); ++it)
        if(*it == tuple)
        {
            tuples.erase(it);
            return;
        }
}

bool checkIfStringComparision(std::string condition)
{
    if(condition == "*:*")
    {
        throw GeneralConditionException();
    }
    else if(condition.substr(0, 6) == "string")
    {
        return true;
    }
    else if(condition.substr(0, 7) == "integer")
    {
        return false;
    }
    else
    {
        throw InvalidConditionException();
    }
}

int getOperatorType(std::string condition, size_t operator_pos, int & operatorLength)
{
    if(condition.substr(operator_pos, 1) == ":")
    {
        if(condition.substr(operator_pos + 1, 1) == ">")
        {
            operatorLength = 2;
            return GTE;
        }
        else if(condition.substr(operator_pos + 1, 1) == "<")
        {
            operatorLength = 2;
            return LTE;
        }
        else
            return EQUAL;
    }
    else if(condition.substr(operator_pos, 1) == ">")
        return GT;
    else if(condition.substr(operator_pos, 1) == "<")
        return LT;
    else
    {
        throw InvalidOperatorException();
    }
}

std::string getConditionValue(std::string condition, size_t operator_pos, int operatorLength, bool stringComparision)
{
    std::string value = condition.substr(operator_pos + operatorLength);
    if(stringComparision && value != "*")
    {
        if(value[0] != '"' || value[value.size()-1] != '"')
        {
            throw InvalidStringFormatException();
        }
        else
           return value.substr(1, value.size() - 2);
    }

    return value;
}

void filterTuples(std::vector<Tuple> &tuples, std::string value, int operatorType, unsigned index, bool stringComparision)
{
    for(std::vector<Tuple>::iterator it = tuples.begin(); it != tuples.end(); ++it)
    {
        if(stringComparision)
        {
            if((*it)[index].isInteger)
            {
                tuples.erase(it--);
            }
            else
            {
                if(value != "*")
                {
                    switch(operatorType)
                    {
                        case EQUAL : if((*it)[index].eString != value) tuples.erase(it--); break;
                        case GT : if((*it)[index].eString <= value) tuples.erase(it--); break;
                        case GTE : if((*it)[index].eString < value) tuples.erase(it--); break;
                        case LT : if((*it)[index].eString >= value) tuples.erase(it--); break;
                        case LTE : if((*it)[index].eString > value) tuples.erase(it--); break;
                    }
                }
            }
        }
        else
        {
            if(!(*it)[index].isInteger)
            {
                tuples.erase(it--);
            }
            else
            {
                if(value != "*")
                {
                    switch(operatorType)
                    {
                        case EQUAL : if((*it)[index].eInteger != atoi(value.c_str())) tuples.erase(it--); break;
                        case GT : if((*it)[index].eInteger <= atoi(value.c_str())) tuples.erase(it--); break;
                        case GTE : if((*it)[index].eInteger < atoi(value.c_str())) tuples.erase(it--); break;
                        case LT : if((*it)[index].eInteger >= atoi(value.c_str())) tuples.erase(it--); break;
                        case LTE : if((*it)[index].eInteger > atoi(value.c_str())) tuples.erase(it--); break;
                    }
                }
            }
        }
    }
}

// @TODO: workPoints = 3 Zaimplementować
void linda_output(char * readBuffer, char * answerBuffer, std::vector<Tuple> &tuples, std::vector<std::string> &tupleRequests, int answerPipes[NRPROC][2])
{
    std::string readBufferString(readBuffer);
    std::string childNumber = readBufferString.substr(0, readBufferString.find("."));
    readBufferString = readBufferString.substr(readBufferString.find(".", readBufferString.find(".") + 1) + 1);
   // printf("STRING is: %s\n", readBufferString.c_str());

    Tuple NewTuple;
    std::string HelpStr;
    try
    {
    for(int i=0; i<= readBufferString.size(); i++)
    {
        if(readBufferString[i]==',')
        {

            if(HelpStr[0]=='"')
            {
                if(HelpStr[(HelpStr.size()-1)]!='"')throw InvalidStringFormatException();
                NewTuple.push_back(Element(HelpStr.substr(1,HelpStr.size()-2)));
            }
            else
            {
                if(HelpStr[(HelpStr.size()-1)]=='"')throw InvalidStringFormatException();
                NewTuple.push_back(Element(atoi(HelpStr.c_str())));
            }

            //printf("SUBSTRING is: %s\n", HelpStr.c_str());
            HelpStr.clear();
        }
        else if(i==readBufferString.size()-1)
        {
            HelpStr+=readBufferString[i];
            if(HelpStr[0]=='"')
            {
                if(HelpStr[(HelpStr.size()-1)]!='"')throw InvalidStringFormatException();
                NewTuple.push_back(Element(HelpStr.substr(1,HelpStr.size()-2)));
            }
            else
            {
                if(HelpStr[(HelpStr.size()-1)]=='"')throw InvalidStringFormatException();
                NewTuple.push_back(Element(atoi(HelpStr.c_str())));
            }

            //printf("SUBSTRING is: %s\n", HelpStr.c_str());
            HelpStr.clear();
        }
        else
        HelpStr+=readBufferString[i];
      }
   }
   catch(InvalidStringFormatException &e)
   {
     perror(e.what());
     std::string answerBufferString = childNumber + "." + "InvalidStringFormatException";
     strcpy(answerBuffer, answerBufferString.c_str());
     return;
   }

    std::vector<Tuple> helpTuples;
    helpTuples.push_back(NewTuple);

    for(std::vector<std::string>::iterator it = tupleRequests.begin(); it != tupleRequests.end(); ++it)
    {
        char answerFromLinda[SIZE_OF_PIPE];
        try
        {
            if(helpTuples.size() == 0)
                break;
            int operation = getOperationFromBuffer(strdup((*it).c_str()));
            switch(operation)
            {
                case LINPUT: linda_match(strdup((*it).c_str()), answerFromLinda, helpTuples, true); break;
                case LREAD: linda_match(strdup((*it).c_str()), answerFromLinda, helpTuples, false); break;
            }

            std::string answerFromLindaString(answerFromLinda);
            std::string addresseeString = answerFromLindaString.substr(0, answerFromLindaString.find("."));
            int addressee = atoi(addresseeString.c_str());
            int offset = addresseeString.length()+1;

            tupleRequests.erase(it--);
            write(answerPipes[addressee][WRITE], answerFromLinda+offset, strlen(answerFromLinda));
            
        }
        catch(TupleNotFoundException &e) {}
    }

    // element nie byl oczekiwany przez żadnego z potomków, bądź był zażądany przy użyciu funkcji linda_read (nieusuwającej)
    if(helpTuples.size() != 0)
        tuples.push_back(NewTuple);

    std::string answerBufferString = childNumber + "." + "SuccessfullyAddedNewTuple";
    strcpy(answerBuffer, answerBufferString.c_str());

}

//@TODO: Zaimplementować
// Funkcja służy do usuwania z pamięci żądań, żądania, które nie musi zostać już obsłużone ze względu na timeout
void deleteFromTupleRequests(char * readBuffer, char* answerBuffer, std::vector<std::string> &tupleRequests)
{
	std::string readBufferString(readBuffer);
	std::string childNumber = readBufferString.substr(0, readBufferString.find("."));


	//usun zadanie;
	bool ifDeleted=false;
	//std::vector<std::string> tupleRequests;
	for(std::vector<std::string>::iterator it=tupleRequests.begin(); it!=tupleRequests.end(); ++it) {
		std::string req=(*it);
		std::string numChild=req.substr(0, req.find("."));
		if(childNumber==numChild) {
			tupleRequests.erase(it);
			ifDeleted=true;
			break;
		}
	}

	std::string answerBufferString;

	if(ifDeleted)
		answerBufferString = childNumber + "." + "SuccessfullyCanceledRequest";
	else
		answerBufferString = childNumber + "." + "NotSuccessfullyCanceledRequest";
	strcpy(answerBuffer, answerBufferString.c_str());

}
